-module(logic_gate_way).
-behaviour(gen_server).

-export([start_link/1, stop/0, init/1, handle_cast/2, handle_info/2, terminate/2, code_change/3, handle_call/3]). 
-include("common.hrl").

-record(state, {sock = 0, sid = 0, hid = 0, uid = 0, aid = 0  , step = 0   ,scene_pid, recv = 0, send=0, prev=0}).


start_link(_) ->
    gen_server:start_link(?MODULE, [], []).

stop() ->  
    gen_server:cast(?MODULE, stop).

init([]) ->
    {ok, #state{sid = self()}}.

handle_info({tcp, _Socket, Data}, #state{recv = Recv} = State) ->
%% 	?log("get Data = ~p",[Data]),
%% ?log("State=~p",[State]),
    case Recv == 0 of	
        true ->
            Packet = Data;
        _ ->
            Packet = list_to_binary([ Recv, Data ])
    end,
	
	case parse(State, Packet) of
%% 		{ok, tgw} -> {noreply, State};
%% 		{ok, policy} -> {stop, normal, State};
		{ok, Remain} -> {noreply, State#state{recv = Remain}};
		_ -> ?log_error("msg parse error")
	end;

handle_info({tcp_closed, _Socket}, #state{uid = Uid,aid=Aid} =State) ->
	?log_trace("tcp_closed uid=~p,aid=~p,reson=~p",[Uid,Aid,"tcp closed"]),
	close_tcp(State),
    {stop, normal, State}.

terminate(_Reason, State) ->
    close_tcp(State),
    ok.

code_change(_OldVsn, State, _Extra) ->    
    {ok, State}.

handle_call(_Request, _From, State) ->    
    {reply, ok, State}.

handle_cast({accept, Sock}, State) ->
	?debug("accept"),
    case gen_tcp:accept(Sock) of
        {ok, Socket} ->
			?debug("accepted"),
            inet:setopts(Socket, [binary, {active, true}]),
            logic_gate_way_sup:relay(Sock),
			notify_add_con(),
            {noreply, State#state{sock = Socket}};

        {error, Reason} ->
            ?log_error("accept error, Reason = ~p ~n", [Reason]),
            logic_gate_way_sup:relay(Sock),
            {stop, accept_error, State}
    end;

handle_cast(flush, #state{sock = Socket, prev = Prev} = State) ->
    P = list_to_binary(lists:reverse(Prev)),
    gen_tcp:send(Socket, P),
    {noreply, State#state{send = 0, prev = 0}};


%% handle_cast({sends, Datas}, State) ->
%%     Fun = fun(Elem, AccIn) ->
%%             Len = byte_size(Elem),
%%             Packet = << 0:16/integer, Len:16/integer, Elem/binary >>,
%%             gen_server:cast(self(), {send, Packet}),
%%             AccIn + 1
%%     end,
%%     lists:foldl(Fun, 0, lists:reverse(Datas)),
%%     {noreply, State};

handle_cast({send, Data}, #state{sock=Socket} = State) ->
	?debug("Data=~p",[Data]),
	gen_tcp:send(Socket, Data),
    {noreply, State#state{}};
handle_cast({amend_mynet_hid,Uid}, State) ->
	{noreply, State#state{uid = Uid, hid = 0}};

handle_cast({set_val, Uid,Pid},  State) ->
	?debug("set_val=~p",[{Uid,Pid}]),
    {noreply, State#state{uid = Uid, hid = Pid}};
handle_cast({set_scene_pid, ScenePid},  State) ->
    {noreply, State#state{scene_pid=ScenePid}};
handle_cast({discon, Reason}, #state{uid = Uid,aid=Aid} = State) ->
	?log_warning("discon uid=~p,aid=~p,reson=~p",[Uid,Aid,Reason]),
    gen_tcp:close(State#state.sock),
    {stop, normal, State};

handle_cast(Msg,#state{uid = Uid,aid=Aid} =State) ->
	?log_error("mynet can not match uid=~p,aid=~p,msg=~p",[Uid,Aid,Msg]),
     {noreply, State}.

%% private function %%

parse(#state{sock = Socket,sid = Sid} = State, Packet) ->
%%  	?debug("Packet=~p",[Packet]),
    case Packet of
		<< Len:?u32, Remain/binary >> ->
			BodyLen = Len - ?HEADER_LENGTH,		
			?debug("Packet=~p~n,Len=~p,BodyLen=~p,Remain=~p",[Packet,Len,BodyLen,Remain]),
			if 
				BodyLen < ?MINI_BODY ->	?discon(Sid,'msg error minibody',400),{ok, 0};
				BodyLen > ?MAX_BODY  -> ?discon(Sid,'msg error maxbody',400),{ok, 0};
				true ->
					case Remain of
						<<Data:BodyLen/binary, Remain2/binary >> ->	
							?debug("Data=~p,Remain2=~p",[Data,Remain2]),
							on_packet_recv(State, Data),
							case byte_size(Remain2) > 0 of
				                true ->
				                    parse(State, Remain2);
				                _ ->
				                    {ok, 0}
				            end;
						_ ->
					         {ok, Packet}
					end
			end;
		_ -> {ok, Packet}        
    end.

close_tcp(#state{uid = Uid, sid = Sid, hid = Hid,scene_pid=ScenePid}) ->	
    if 
        Hid == 0 -> gen_server:cast({global, login}, {tcp_closed, Sid});
        is_pid(Hid) ->gen_server:cast(Hid, {tcp_closed, Uid, Sid});
        true -> gen_server:cast({global, Hid}, {tcp_closed, Uid, Sid}) 
    end,
	if
		ScenePid==0->skip;
		true-> gen_server:cast(ScenePid, {tcp_closed, Uid})
	end,
	notify_discon().

get_ip(Socket)->
	case inet:peername(Socket) of
		{ok,{Address,_Port}}->Address;
		_-> {0,0,0,0}
	end.
	
on_packet_recv(#state{sock = Socket,sid = Sid,scene_pid=ScenePid, uid = Uid, hid = Hid}, Data) ->					
	case pt:read_short(Data)of 
		{?PT_ASK_PING, Rest}->
			Bin=pt:pack(?PT_ASK_PING, Rest),
			?debug("Ping=~p",[Bin]),
			?send(Sid, Bin);
		{Cmd,Rest}->
			router:handle(Cmd, Rest, ScenePid, Uid, Sid);
		_->?log_error("error data")
end.

notify_add_con() ->skip.
%% 	MynetID=db:get_all_config(mynet_id),
%% 	gen_server:cast({global, mynet_mng}, {add_con, MynetID}).
notify_discon() ->skip.
%% 	MynetID=db:get_all_config(mynet_id),
%% 	gen_server:cast({global, mynet_mng}, {discon, MynetID}).

